package cn.com.artemis.security;

import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * 登录成功后生成token
 * </p>
 *
 * @author enbool
 * @since 2020-06-09
 */
public class GrantTokenService {
    public GrantTokenService(AuthorizationServerTokenServices tokenServices, PasswordEncoder passwordEncoder, ClientDetailsService clientDetailsService) {
        this.tokenServices = tokenServices;
        this.passwordEncoder = passwordEncoder;
        this.clientDetailsService = clientDetailsService;
    }

    private AuthorizationServerTokenServices tokenServices;

    private PasswordEncoder passwordEncoder;

    private ClientDetailsService clientDetailsService;


    public OAuth2AccessToken grant(String authorization, Authentication authentication) throws IOException {

        String[] client = extractAndDecodeHeader(authorization);
        assert client.length == 2;

        String clientId = client[0];

        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);

        if (clientDetails == null) {
            throw new UnapprovedClientAuthenticationException("clientId对应的配置信息不存在：" + clientId);
        } else if (!passwordEncoder.matches(client[1], clientDetails.getClientSecret())) {
            throw new UnapprovedClientAuthenticationException("clientSecret不匹配");
        }

        Set<String> scopes = new HashSet<>();
        scopes.add("all");
        Map<String, String> requestParameters= new HashMap<>();
        TokenRequest tokenRequest = new TokenRequest(requestParameters, clientId, clientDetails.getScope(), "password");
        OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);

        OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);

        OAuth2AccessToken token = tokenServices.createAccessToken(oAuth2Authentication);

        return token;
    }

    private String[] extractAndDecodeHeader(String header) throws IOException {

        byte[] base64Token = header.substring(6).getBytes("UTF-8");
        byte[] decoded;
        try {
            decoded = Base64.decode(base64Token);
        } catch (IllegalArgumentException e) {
            throw new BadCredentialsException("Failed to decode basic authentication token");
        }

        String token = new String(decoded, "UTF-8");

        int delim = token.indexOf(":");

        if (delim == -1) {
            throw new BadCredentialsException("Invalid basic authentication token");
        }
        return new String[]{token.substring(0, delim), token.substring(delim + 1)};
    }
}
